use crate::features::quizzes::{
  self,
  modelsgqo::{AddEBPQuizIn, Quiz},
};

use crate::features::tasks::{
  self,
  modelsgqo::{AnswerTaskQuizItemIn, Task},
};

use crate::dbs::sqlite::Peer;
use crate::features::explorer::modelsgqo::{
  CloseEditor, Editor, EditorFilterIn, File, Folder, NewFile, NewFolder, OpenEditor, UpdateFile,
  UpdateFolder,
};
use crate::features::explorer::{self};
use crate::features::sgraph::modelsgqo::Nodedge;
use crate::features::users::{
  self,
  modelsdbo::{NewUser, UserDBO},
  modelsgqo::{SignIn, User},
};
use async_graphql::{Context, ID};
use async_graphql::{Error, ErrorExtensions};
use rbatis::rbatis::Rbatis;

use crate::util::constant::GqlResult;

pub struct MutationRoot;

#[async_graphql::Object]
impl MutationRoot {
  /// 把试卷加入个人艾宾遗忘曲线对抗清单EBP（Ebbinghaus Programme）
  async fn add_ebp_quiz(&self, ctx: &Context<'_>, input: AddEBPQuizIn) -> GqlResult<Quiz> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    let my_peer = ctx.data_unchecked::<Peer>();

    let db_result =
      quizzes::services::add_ebp_quizitems_to_tasks(rbatis_pool, my_peer, &input.id.0).await;

    if db_result.is_ok() {
      Ok(db_result.unwrap().into())
    } else {
      Err(
        Error::new("2-FAILED-ADD-EBP-QUIZ")
          .extend_with(|_, e| e.set("details", "Failed to add Quiz and QuizItems to your tasks")),
      )
    }
  }

  /// 回答试题任务TaskQuizItem
  async fn answer_task_quizitem(
    &self,
    ctx: &Context<'_>,
    input: AnswerTaskQuizItemIn,
  ) -> GqlResult<Task> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    let my_peer = ctx.data_unchecked::<Peer>();

    let std_answer = input.std_answer;
    let answer = input.answer;
    let seconds = input.seconds;

    let quiz_dbo = tasks::services::answer_task_quizitem(
      rbatis_pool,
      my_peer,
      &input.task_id,
      &std_answer,
      &answer,
      seconds,
    )
    .await;

    if quiz_dbo.is_ok() {
      Ok(quiz_dbo.unwrap().into())
    } else {
      Err(Error::new("id 不存在").extend_with(|_, e| e.set("details", "1_ID_NOT_EXIStS")))
    }
  }

  /// 插入新用户
  async fn new_user(&self, ctx: &Context<'_>, new_user: NewUser) -> GqlResult<User> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    users::services::new_user(rbatis_pool, new_user).await
  }

  /// user sign in
  async fn sign_in(&self, ctx: &Context<'_>, input: SignIn) -> Result<String, Error> {
    //let maybe_user = repository::get_user(&input.username, &get_conn_from_ctx(ctx)).ok();
    //
    //if let Some(user) = maybe_user {
    //    if let Ok(matching) = verify_password(&user.hash, &input.password) {
    //        if matching {
    //            let role = AuthRole::from_str(user.role.as_str()).expect("Can't convert &str to AuthRole");
    //            return Ok(common_utils::create_token(user.username, role));
    //        }
    //    }
    //}

    Err(Error::new("Can't authenticate a user"))
  }

  /// create folder
  async fn new_folder(&self, ctx: &Context<'_>, input: NewFolder) -> GqlResult<Folder> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    let my_peer = ctx.data_unchecked::<Peer>();
    explorer::services::new_folder(rbatis_pool, input).await
  }

  /// update folder
  async fn update_folder(
    &self,
    ctx: &Context<'_>,
    folder_id: ID,
    input: UpdateFolder,
  ) -> GqlResult<Folder> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    explorer::services::update_folder(rbatis_pool, &folder_id.0, input).await
  }

  /// create file
  async fn new_file(&self, ctx: &Context<'_>, input: NewFile) -> GqlResult<File> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    explorer::services::new_file(rbatis_pool, input).await
  }

  /// update file
  async fn update_file(
    &self,
    ctx: &Context<'_>,
    file_id: ID,
    input: UpdateFile,
  ) -> GqlResult<File> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    explorer::services::update_file(rbatis_pool, &file_id.0, input).await
  }

  async fn open_editor(&self, ctx: &Context<'_>, input: OpenEditor) -> GqlResult<Editor> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    explorer::services::open_editor(rbatis_pool, input).await
  }

  async fn close_editor(&self, ctx: &Context<'_>, input: CloseEditor) -> GqlResult<Editor> {
    let rbatis_pool = ctx.data_unchecked::<Rbatis>();
    explorer::services::close_editor(rbatis_pool, input).await
  }

  
}
